home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Xconq 7.0d37 / source / curses / ccmd.c next >
Encoding:
C/C++ Source or Header  |  1995-05-04  |  24.4 KB  |  1,197 lines  |  [TEXT/KAHL]

  1. /* Commands for the curses interface to Xconq.
  2.    Copyright (C) 1986, 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995
  3.    Stanley T. Shebs.
  4.  
  5. Xconq is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.  See the file COPYING.  */
  9.  
  10. #include "conq.h"
  11. #include "cconq.h"
  12. int ask_direction PROTO ((char *prompt, int *dirp));
  13.  
  14. /* Command table. */
  15.  
  16. typedef struct cmdtab {
  17.     char fchar;                 /* character to match against */
  18.     char *name;                 /* Full name of command */
  19.     char *argtypes;
  20.     void (*fn) PROTO ((void));  /* pointer to command's function */
  21.     char *help;                 /* short documentation string */
  22. } CmdTab;
  23.  
  24. static void resize_map PROTO ((int n));
  25. static void execute_named_command PROTO ((char *cmdstr));
  26. static int execute_command_from_table PROTO ((CmdTab *cmdtab));
  27. static int execute_named_command_from_table PROTO ((char *cmdstr,
  28.                             CmdTab *cmdtab));
  29. static void describe_commands PROTO ((int arg, char *key, char *buf));
  30. static void describe_command_table PROTO ((int arg, char *key, char *buf, CmdTab *cmdtab));
  31. static void describe_help PROTO ((int arg, char *key, char *buf));
  32. static void cmd_error PROTO ((char *fmt, ...));
  33.  
  34. /* Declarations of all the command functions. */
  35.  
  36. #undef DEF_CMD
  37. #define DEF_CMD(letter,name,args,FN,help) void FN PROTO ((void));
  38.  
  39. #include "cmd.def"
  40.  
  41. #include "ccmd.def"
  42.  
  43. /* Define a table of generic commands. */
  44.  
  45. #define C(c) ((c)-0x40)
  46.  
  47. CmdTab commands[] = {
  48.  
  49. #undef DEF_CMD
  50. #define DEF_CMD(LETTER,NAME,ARGS,FN,HELP) { LETTER, NAME, ARGS, FN, HELP },
  51.  
  52. #include "cmd.def"
  53.  
  54.   { 0, NULL, NULL, NULL, NULL }
  55. };
  56.  
  57. /* Define a table of curses-specific commands. */
  58.  
  59. CmdTab ccommands[] = {
  60.  
  61. #include "ccmd.def"
  62.  
  63.   { 0, NULL, NULL, NULL, NULL }
  64. };
  65.  
  66. /* Use this macro in any command if it requires a current unit. */
  67.  
  68. #define REQUIRE_UNIT()  \
  69.   if (!in_play(curunit)) {  \
  70.     curunit = NULL;  \
  71.     cmd_error("No current unit");  \
  72.     return;  \
  73.   }
  74.  
  75. Unit *lastactor = NULL;
  76.  
  77. Unit *
  78. find_next_and_look()
  79. {
  80.     Unit *nextunit, *unit;
  81.  
  82.     nextunit = find_next_actor(dside, curunit);
  83.     if (nextunit != NULL) {
  84.     make_current(nextunit);
  85.     show_cursor();
  86.     }
  87.     return nextunit;
  88. }
  89.  
  90. void
  91. do_add_player()
  92. {
  93.     cmd_error("command not implemented");
  94. }
  95.  
  96. void
  97. do_add_terrain()
  98. {
  99.     int u, t, dir;
  100.  
  101.     REQUIRE_UNIT();
  102.     u = curunit->type;
  103.     if (ask_direction("Add terrain to where?", &dir)) {
  104.     for_all_terrain_types(t) {
  105.         if (ut_acp_to_add_terrain(u, t) > 0
  106.         && curunit->act
  107.         && curunit->act->acp >= ut_acp_to_add_terrain(u, t)) {
  108.         if (0 <= ut_alter_range(curunit->type, t)) {
  109.             if (prep_add_terrain_action(curunit, curunit,
  110.                         curunit->x, curunit->y,
  111.                         dir, t))
  112.               ;
  113.             else
  114.               xbeep();
  115.         }
  116.         }
  117.     }
  118.     }
  119. }
  120.  
  121. /* Set which AI is to run the side's play. */
  122.  
  123. void
  124. do_ai_side()
  125. {
  126.     if (side_has_ai(dside)) {
  127.     set_side_ai(dside, NULL);
  128.     } else {
  129.     set_side_ai(dside, "mplayer");
  130.     }
  131. }
  132.  
  133. void
  134. do_attack()
  135. {
  136.     int x, y, rslt;
  137.     Unit *other;
  138.  
  139.     REQUIRE_UNIT();
  140.     if (ask_position("Attack where?", &x, &y)) {
  141.     for_all_stack(x, y, other) {
  142.         if (!unit_trusts_unit(curunit, other)) {
  143.         if (valid(check_attack_action(curunit, curunit, other, 100))) {
  144.             prep_attack_action(curunit, curunit, other, 100);
  145.             return;
  146.         }
  147.         /* (should try other types of actions?) */
  148.         }
  149.     }
  150.     cmd_error("Nothing for %s to attack at %d,%d!",
  151.           unit_handle(dside, curunit), x, y);
  152.     }
  153. }
  154.  
  155. /* Set the unit to automatic control.  */
  156.  
  157. void
  158. do_auto()
  159. {
  160.     REQUIRE_UNIT();
  161.     if (curunit->plan) {
  162.     curunit->plan->autotask = !curunit->plan->autotask;
  163.     /* finish move under automatic control */
  164.     }
  165. }
  166.  
  167. void
  168. do_build()
  169. {
  170.     int u2;
  171.  
  172.     REQUIRE_UNIT();
  173.     if (!can_build(curunit)) {
  174.     cmd_error("%s can't build anything!", unit_handle(dside, curunit));
  175. #if 0
  176.     } else if (!u_occproduce(curunit->type) && curunit->transport != NULL) {
  177.     cmd_error("%s can't build anything while inside another unit!",
  178.           unit_handle(dside, curunit));
  179. #endif
  180.     } else {
  181.     u2 = ask_unit_type("Type to create:", NULL);
  182.     if (u2 != NONUTYPE) {
  183.         notify(dside, "%s will build %d %s",
  184.            unit_handle(dside, curunit), 99, u_type_name(u2));
  185.         push_build_task(curunit, u2, 99);
  186.     } else {
  187.         /* should clear toplines */
  188.     }
  189.     }
  190. }
  191.  
  192. void
  193. do_clear_plan()
  194. {
  195.     REQUIRE_UNIT();
  196.     if (curunit->plan) {
  197.     set_unit_plan_type(dside, curunit, PLAN_NONE);
  198.     }
  199. }
  200.  
  201. void
  202. do_copying()
  203. {
  204.     notify(dside, "You may copy freely.  See the file COPYING.");
  205. }
  206.  
  207. void
  208. do_delay()
  209. {
  210.     Unit *oldcurunit = curunit, *nextmover;
  211.  
  212.     nextmover = find_next_and_look();
  213.  
  214.     if (nextmover == NULL) {
  215.     cmd_error("no units???");
  216.     } else if (curunit == oldcurunit) {
  217.     notify(dside, "No other units to move!");
  218.     }
  219. }
  220.  
  221. void
  222. do_detach()
  223. {
  224.     cmd_error("command not implemented");
  225. }
  226.  
  227. void
  228. do_detonate()
  229. {
  230.     Unit *unit = curunit;
  231.  
  232.     REQUIRE_UNIT();
  233.     prep_detonate_action(unit, unit, unit->x, unit->y, unit->z);
  234. }
  235.  
  236. /* Supposedly you could only get to these by typing the full command names. */
  237.  
  238. void
  239. do_dir()
  240. {
  241.     cmd_error("use the single-character commands instead");
  242. }
  243.  
  244. void
  245. do_dir_multiple()
  246. {
  247.     cmd_error("use the single-character commands instead");
  248. }
  249.  
  250. /* Get rid of a unit. */
  251.  
  252. void
  253. do_disband()
  254. {
  255.     int u;
  256.  
  257.     REQUIRE_UNIT();
  258.     u = curunit->type;
  259. #ifdef DESIGNERS
  260.     if (dside->designer) {
  261.     kill_unit(curunit, -1);
  262.     return;
  263.     }
  264. #endif /* DESIGNERS */
  265.     if (u_hp_per_disband(u) > 0) {
  266.     if (prep_disband_action(curunit, curunit)) {
  267.         /* (text should come from game design) */
  268.         notify(dside, "%s will go home.", unit_handle(dside, curunit));
  269.     } else {
  270.         /* failed, should say something */
  271.     }
  272.     } else {
  273.     cmd_error("You can't just get rid of %s!",
  274.           unit_handle(dside, curunit));
  275.     }
  276. }
  277.  
  278. /* Determine how far away another point is.  */
  279.  
  280. void
  281. do_distance()
  282. {
  283.     int x, y;
  284.  
  285.     if (ask_position("Distance to where?", &x, &y)) {
  286.     notify(dside, "Distance is %d cells.", distance(curx, cury, x, y));
  287.     }
  288. }
  289.  
  290. /* What about trying to embark a unit on itself or on its previous transp? */
  291.  
  292. void
  293. do_embark()
  294. {
  295.     Unit *transport;
  296.  
  297.     REQUIRE_UNIT();
  298.     if (ask_unit("Which unit to board?", &transport)) {
  299.     if (!in_play(transport)) {
  300.         cmd_error("This transport is nonsensical");
  301.     } else if (!can_occupy(curunit, transport)) {
  302.         cmd_error("Can't occupy");
  303.     } else {
  304.         prep_enter_action(curunit, curunit, transport);
  305.         /* (should be able to set up task if can't do action immedly) */
  306.     }
  307.     }
  308. }
  309.  
  310. /* Command to end our activity for this turn. */
  311.  
  312. void
  313. do_end_turn()
  314. {
  315.     finish_turn(dside);
  316. }
  317.  
  318. /* Command to fire at a specified unit or location. */
  319.  
  320. void
  321. do_fire()
  322. {
  323.     int x, y;
  324.     Unit *unit2;
  325.  
  326.     REQUIRE_UNIT();
  327.     sprintf(spbuf, "Fire %s at where?", unit_handle(dside, curunit));
  328.     /* (should have some sort of range feedback) */
  329.     if (ask_position(spbuf, &x, &y)) {
  330.     for_all_stack(x, y, unit2) {
  331.         if (g_see_all() /* or under observation in some way */
  332.         && unit2->side != curunit->side) {
  333.         prep_fire_at_action(curunit, curunit, unit2, -1);
  334.         return;
  335.         }
  336.     }
  337.     /* (should say that nothing is visible and verify firing) */
  338.     if (1) {
  339.         prep_fire_into_action(curunit, curunit, x, y, 0, -1);
  340.     } else {
  341.         xbeep();
  342.     }
  343.     }
  344. }
  345.  
  346. void
  347. do_fire_into()
  348. {
  349. }
  350.  
  351. /* Give supplies to a transport.  The argument tells how many to give. */
  352.  
  353. void
  354. do_give()
  355. {
  356.     int n = cmdarg, something = FALSE, u, m, r, gift, actual;
  357.     Unit *main;
  358.  
  359.     REQUIRE_UNIT();
  360.     u = curunit->type;
  361.     main = curunit->transport;
  362.     if (main != NULL) {
  363.     sprintf(spbuf, "");
  364.     m = main->type;
  365.     for_all_material_types(r) {
  366.         gift = (n < 0 ? (um_storage_x(m, r) - main->supply[r]) : n);
  367.         if (gift > 0) {
  368.         something = TRUE;
  369.         /* Be stingy if we're low */
  370.         if (2 * curunit->supply[r] < um_storage_x(u, r))
  371.             gift = max(1, gift/2);
  372.         actual = transfer_supply(curunit, main, r, gift);
  373.         sprintf(tmpbuf, " %d %s", actual, m_type_name(r));
  374.         strcat(spbuf, tmpbuf);
  375.         }
  376.     }
  377.     if (something) {
  378.         notify(dside, "%s gave%s.", unit_handle(dside, curunit), spbuf);
  379.     } else {
  380.         notify(dside, "%s gave nothing.", unit_handle(dside, curunit));
  381.     }
  382.     } else {
  383.     cmd_error("Can't transfer supplies here!");
  384.     }
  385. }
  386.  
  387. /* Give a unit to another side or "to" independence. */
  388.  
  389. void
  390. do_give_unit()
  391. {
  392.     int u;
  393.  
  394.     REQUIRE_UNIT();
  395.     u = curunit->type;
  396. #ifdef DESIGNERS
  397.     if (dside->designer) {
  398.     unit_changes_side(curunit, side_n(cmdarg), -1, -1);
  399.     /* (should update_unit_display also?) */
  400.     all_see_cell(curunit->x, curunit->y);
  401.     return;
  402.     }
  403. #endif /* DESIGNERS */
  404.     if (1) { /* (should test both temporary and permanent invalidity) */
  405.     prep_change_side_action(curunit, curunit, side_n(cmdarg));
  406.     } else {
  407.     cmd_error("You can't just give away the %s!", u_type_name(u));
  408.     }
  409. }
  410.  
  411. /* Bring up help info. */
  412.  
  413. static void
  414. describe_help(arg, key, buf)
  415. int arg;
  416. char *key, *buf;
  417. {
  418.     sprintf(buf, "duh");
  419. }
  420.  
  421. void
  422. do_help()
  423. {
  424.     /* Switch to help mode. */
  425.     prevmode = mode;
  426.     mode = HELP;
  427.     /* Get a help node and display its content. */
  428.     if (cur_help_node == NULL) {
  429.     help_help_node =
  430.       add_help_node("help", describe_help, 0, firsthelpnode);
  431.     add_help_node("commands", describe_commands, 0, firsthelpnode);
  432.     topics_help_node =
  433.       add_help_node("topics", describe_topics, 0, firsthelpnode);
  434.     cur_help_node = topics_help_node;
  435.     }
  436.     helpstring = get_help_text(cur_help_node);
  437.     show_help();
  438.     refresh();
  439. }
  440.  
  441. /* Send a short message to another side. */
  442.  
  443. void
  444. do_message()
  445. {
  446.     char *msg;
  447.     Side *side3 = NULL;
  448.  
  449.     if (cmdarg == 0) {
  450.     /* (should ask who to send to) */
  451.     }
  452.     if (ask_string("Message: ", "", &msg)) {
  453.     if (strlen(msg) == 0) {
  454.         notify(dside, "You keep your mouth shut.");
  455.     } else if (1 /* broadcast? */) {
  456.         if (strlen(msg) > 0) {
  457.         notify(dside, "You announce: %s", msg);
  458.         }
  459.     } else {
  460.         notify(dside, "You send your message (?)");
  461.     }
  462.     }
  463. }
  464.  
  465. /* Set unit to move to a given location.  Designers do a teleport. */
  466.  
  467. void
  468. do_move_to()
  469. {
  470.     int x, y;
  471.  
  472.     REQUIRE_UNIT();
  473.     sprintf(spbuf, "Move %s to where?", unit_handle(dside, curunit));
  474.     if (ask_position(spbuf, &x, &y)) {
  475. #ifdef DESIGNERS
  476.     if (dside->designer) {
  477.         designer_teleport(curunit, x, y);
  478.         make_current(curunit);
  479.         return;
  480.     }
  481. #endif /* DESIGNERS */
  482.     order_moveto(curunit, x, y);
  483.     }
  484. }
  485.  
  486. /* Command to name or rename the current unit or a given side. */
  487.  
  488. void
  489. do_name()
  490. {
  491.     char *newname;
  492.  
  493.     REQUIRE_UNIT();
  494.     if (ask_string("New name for unit:", curunit->name, &newname)) {
  495.       if (strlen(newname) == 0)
  496.     newname = NULL;
  497.       set_unit_name(dside, curunit, newname);
  498.     }
  499. }
  500.  
  501. void
  502. do_other()
  503. {
  504.     char *cmd;
  505.  
  506.     if (ask_string("ext cmd # ", NULL, &cmd)) {
  507.     if (empty_string(cmd)) {
  508.         cmd_error("No command");
  509.     } else if (strcmp(cmd, "?") == 0) {
  510.         do_help();
  511.         /* (should go to command list specifically) */
  512.     } else {
  513.         execute_named_command(cmd);
  514.     }
  515.     }
  516. }
  517.  
  518. void
  519. do_print_view()
  520. {
  521.     dump_text_view(dside);
  522. }
  523.  
  524. void
  525. do_produce()
  526. {
  527.     cmd_error("command not implemented");
  528. }
  529.  
  530. /* Command to get out of a game, one way or another. */
  531.  
  532. void
  533. do_quit()
  534. {
  535.     Side *side2 = NULL;
  536.  
  537.     if (!dside->ingame) {
  538.     exit_cconq(dside);
  539.     } else if (0 /* other players think they can win */) {
  540.     if (ask_bool("Do you really want to give up?", FALSE)) {
  541.         if (numsides > 2) {
  542. /*        ask_side("Who do you want to surrender to?", NULL); */
  543.         resign_game(dside, side2);
  544.         } else {
  545.         resign_game(dside, NULL);
  546.         }
  547.     }
  548.     } else if (ask_bool("Do you really want to quit now?", FALSE)) {
  549.     /* should force a loss first if necessary. */
  550.     exit_cconq(dside);
  551.     }
  552. }
  553.  
  554. /* Move the current location as close to the center of the display as
  555.    possible, and redraw everything. */
  556.  
  557. void
  558. do_recenter()
  559. {
  560.     set_view_focus(mvp, curx, cury);
  561.     center_on_focus(mvp);
  562.     set_map_viewport();
  563.     show_map();
  564.     refresh();
  565. }
  566.  
  567. /* Redraw everything using the same code as when windows need a redraw. */
  568.  
  569. void
  570. do_refresh()
  571. {
  572.     redraw();
  573. }
  574.  
  575. void
  576. do_remove_terrain()
  577. {
  578.     int t, dir;
  579.  
  580.     REQUIRE_UNIT();
  581.     if (ask_direction("Remove terrain from where?", &dir)) {
  582.       for_all_terrain_types(t) {
  583.     if (ut_acp_to_remove_terrain(curunit->type, t) > 0
  584.         && curunit->act
  585.         && curunit->act->acp >= ut_acp_to_remove_terrain(curunit->type, t)) {
  586.         if (0 <= ut_alter_range(curunit->type, t)) {
  587.         if (prep_remove_terrain_action(curunit, curunit, curunit->x, curunit->y, dir, t))
  588.           ;
  589.         else
  590.           xbeep();
  591.         }
  592.     }
  593.       }
  594.     }
  595. }
  596.  
  597. void
  598. do_reserve()
  599. {
  600.     REQUIRE_UNIT();
  601.     set_unit_asleep(dside, curunit, TRUE, TRUE);
  602. }
  603.  
  604. /* Set unit to return to a good resupply place. */
  605.  
  606. void
  607. do_return()
  608. {
  609.     REQUIRE_UNIT();
  610.     set_resupply_task(curunit);
  611. }
  612.  
  613. /* Stuff game state into a file.  By default, it goes into the current
  614.    directory.  If building a scenario, we can specify just which parts
  615.    of the game state are to be written. */
  616.  
  617. void
  618. do_save()
  619. {
  620.     char *rawcontents;
  621.     Module *module;
  622.     Obj *contents;
  623.     Side *side2;
  624.  
  625. #ifdef DESIGNERS
  626.     if (dside->designer) {
  627.     if (ask_string("Data to write?", "everything", NULL)) {
  628.         /* (should be in a designer_create_module?) */
  629.         /* need to be able to get this name from somewhere */
  630.         module = create_game_module("random.scn");
  631.         /* need something better to turn contents into a Lisp object */
  632.         contents = intern_symbol(rawcontents);
  633.         /*    interpret_content_spec(module, contents);  */
  634.         notify(dside, "Module will be written to \"%s\" ...", module->filename);
  635.         if (write_game_module(module)) {
  636.         notify(dside, "Done writing to \"%s\".", module->filename);
  637.         } else {
  638.         cmd_error("Can't open file \"%s\"!", module->filename);
  639.         }
  640.         return;
  641.     } else {
  642.         return;
  643.     }
  644.     }
  645. #endif /* DESIGNERS */
  646.     if (0 /* checkpointing not allowed */) {
  647.     if (ask_bool("You really want to save and exit?", FALSE)) {
  648.         notify(dside, "Game will be saved to \"%s\" ...", saved_game_filename());
  649.         if (write_entire_game_state(saved_game_filename())) {
  650.         close_displays();
  651.         /* this should be conditional? */
  652.         exit(0);
  653.         } else {
  654.         cmd_error("Can't open file \"%s\"!", saved_game_filename());
  655.         }
  656.     }
  657.     } else {
  658.     notify(dside, "Saving...");
  659.     if (write_entire_game_state(saved_game_filename())) {
  660.         notify(dside, "Game saved.");
  661.     } else {
  662.         cmd_error("Couldn't save to \"%s\"!", saved_game_filename());
  663.     }        
  664.     }
  665. }
  666.  
  667. void
  668. do_set_formation()
  669. {
  670.     Unit *leader;
  671.  
  672.     REQUIRE_UNIT();
  673.     sprintf(spbuf, "Which unit to follow?");
  674.     if (ask_unit(spbuf, &leader)) {
  675.     if (!in_play(leader)) {
  676.         cmd_error("No unit to follow!");
  677.     } else if (leader == curunit) {
  678.         cmd_error("Unit can't follow itself!");
  679.     } else if (leader->side != dside /* or "trusted side"? */) {
  680.         cmd_error("Can't follow somebody else's unit!");
  681.     } else {
  682.         set_formation(curunit, leader, curunit->x - leader->x, curunit->y - leader->y, 1, 1);
  683.     }
  684.     }
  685. }
  686.  
  687. void
  688. do_sleep()
  689. {
  690.     REQUIRE_UNIT();
  691.     set_unit_asleep(dside, curunit, TRUE, TRUE);
  692. }
  693.  
  694. /* Command to toggle between interaction modes. */
  695.  
  696. void
  697. do_survey()
  698. {
  699.     if (mode == MOVE) {
  700.     lastactor = curunit;
  701.     mode = SURVEY;
  702.     } else {
  703.     mode = MOVE;
  704.     /* If we weren't looking at a unit when we switched modes,
  705.        go back to the last unit that was being moved. */
  706.     if (curunit == NULL && in_play(lastactor)) {
  707.         make_current(lastactor);
  708.     }
  709.     }
  710.     show_map();
  711.     refresh();
  712. }
  713.  
  714. /* Take supplies from transport. */
  715.  
  716. void
  717. do_take()
  718. {
  719.     int m, rslt, amts[MAXMTYPES];
  720.  
  721.     REQUIRE_UNIT();
  722.     rslt = take_supplies(curunit, NULL, amts);
  723.     if (rslt) {
  724.     spbuf[0] = '\0';
  725.     for_all_material_types(m) {
  726.         if (amts[m] > 0) {
  727.         sprintf(tmpbuf, " %d %s", amts[m], m_type_name(m));
  728.         strcat(spbuf, tmpbuf);
  729.         }
  730.     }
  731.     notify(dside, "%s got%s.", unit_handle(dside, curunit), spbuf);
  732.     } else {
  733.     notify(dside, "%s got nothing.", unit_handle(dside, curunit));
  734.     }
  735. }
  736.  
  737. void
  738. do_take_unit()
  739. {
  740.     cmd_error("command not implemented");
  741. }
  742.  
  743. #if 0
  744. void
  745. do_undelay()
  746. {
  747.     Unit *nextunit;
  748.  
  749.     if ((nextunit = find_prev_actor(dside, curunit)) != NULL) {
  750.     make_current(nextunit);
  751.     } else {
  752.     xbeep();
  753.     }
  754. }
  755. #endif
  756.  
  757. /* Wake *everything* (that's ours) within the given radius.  Two commands
  758.    actually; "top-level" units (not in a transport) vs all units. */
  759.  
  760. /* Wake top-level units. */
  761.  
  762. void
  763. do_wake()
  764. {
  765.     wake_area(dside, curx, cury, cmdarg, FALSE);
  766. }
  767.  
  768. /* Wake all units found. */
  769.  
  770. void
  771. do_wake_all()
  772. {
  773.     wake_area(dside, curx, cury, cmdarg, TRUE);
  774. }
  775.  
  776. /* Display the program version. */
  777.  
  778. void
  779. do_version()
  780. {
  781.     notify(dside, "Curses Xconq version %s", version_string());
  782.     notify(dside, "(c) %s", copyright_string());
  783. }
  784.  
  785. void
  786. do_warranty()
  787. {
  788.     notify(dside, "There is no warranty.");
  789. }
  790.  
  791. /* Curses-specific commands. */
  792.  
  793. void
  794. do_c_change_list_type()
  795. {
  796.     cycle_list_type();
  797.     show_list();
  798.     refresh();
  799. }
  800.  
  801.  
  802. void
  803. do_c_change_list_filter()
  804. {
  805.     cycle_list_filter();
  806.     show_list();
  807.     refresh();
  808. }
  809.  
  810. void
  811. do_c_change_list_order()
  812. {
  813.     cycle_list_order();
  814.     show_list();
  815.     refresh();
  816. }
  817.  
  818. /* Toggle the action following flag. */
  819.  
  820. void
  821. do_c_follow_action()
  822. {
  823.     follow_action = !follow_action;
  824.     if (follow_action) {
  825.     notify(dside, "Following the action.");
  826.     } else {
  827.     notify(dside, "Not following the action.");
  828.     }
  829. }
  830.  
  831. /* Commands to change the dividing line between the right-hand and left-hand
  832.    windows of the screen. */
  833.  
  834. void
  835. do_c_grow_map()
  836. {
  837.     if (cmdarg < 0)
  838.       cmdarg = 5;
  839.     if (lw - cmdarg < 5) {
  840.     cmd_error("list side must be at least 5");
  841.     return;
  842.     }
  843.     resize_map(cmdarg);
  844. }
  845.  
  846. /* This is a clever (if I do say so myself) command to examine all occupants
  847.    and suboccupants, in an inorder fashion. */
  848.  
  849. /* Should have an option to open up a list window that shows everything
  850.    all at once. */
  851.  
  852. void
  853. do_c_occupant()
  854. {
  855.     Unit *nextup;
  856.  
  857.     REQUIRE_UNIT();
  858.     if (curunit->occupant != NULL) {
  859.     make_current(curunit->occupant);
  860.     } else if (curunit->nexthere != NULL) {
  861.     make_current(curunit->nexthere);
  862.     } else {
  863.     nextup = curunit->transport;
  864.     if (nextup != NULL) {
  865.         while (nextup->transport != NULL && nextup->nexthere == NULL) {
  866.         nextup = nextup->transport;
  867.         }
  868.         if (nextup->nexthere != NULL)
  869.           make_current(nextup->nexthere);
  870.         if (nextup->transport == NULL)
  871.           make_current(nextup);
  872.     } else {
  873.         /* This is a no-op if there is no stacking within a cell. */
  874.         make_current(unit_at(curunit->x, curunit->y));
  875.     }
  876.     }
  877. }
  878.  
  879. void
  880. do_c_shrink_map()
  881. {
  882.     if (cmdarg < 0)
  883.       cmdarg = 5;
  884.     if (mw + cmdarg < 10) {
  885.     cmd_error("map side must be at least 10");
  886.     return;
  887.     }
  888.     resize_map(0 - cmdarg);
  889. }
  890.  
  891. static void
  892. resize_map(n)
  893. int n;
  894. {
  895.     /* Resize the left-hand-side windows. */
  896.     mw += n;
  897.     closeupwin->w += n;
  898.     mapwin->w += n;
  899.     /* Move and resize the right-hand-side windows. */
  900.     lw -= n;
  901.     sideswin->x += n;
  902.     sideswin->w -= n;
  903.     listwin->x += n;
  904.     listwin->w -= n;
  905.     /* Update the screen to reflect the changes. */
  906.     set_scroll();
  907.     redraw();
  908. }
  909.  
  910. void
  911. do_c_use_both_chars()
  912. {
  913.     use_both_chars = !use_both_chars;
  914.     show_map();
  915.     refresh();
  916. }
  917.  
  918. #ifdef DESIGNERS
  919.  
  920. static int check_designer_status PROTO ((char *str));
  921.  
  922. /* The following commands are only available to designers. */
  923.  
  924. int curradius = 0;
  925. int curttype = 0;
  926. int curutype = 0;
  927. int curfeature = 0;
  928. int cursidenumber = 1;
  929.  
  930. static int
  931. check_designer_status(str)
  932. char *str;
  933. {
  934.     if (dside->designer) {
  935.     return TRUE;
  936.     } else {
  937.     cmd_error("You're not a designer, can't %s!", str);
  938.     return FALSE;
  939.     }
  940. }
  941.  
  942. void
  943. do_design()
  944. {
  945.     if (!dside->designer) {
  946.     become_designer(dside);
  947.     } else {
  948.     become_nondesigner(dside);
  949.     }
  950. }
  951.  
  952. void
  953. do_c_set_unit_type()
  954. {
  955.     int u;
  956.  
  957.     if (!check_designer_status("set unit types to create"))
  958.       return;
  959.     u = ask_unit_type("Type of unit to create: ", NULL);
  960.     if (u != NONUTYPE) {
  961.     curutype = u;
  962.     if (cmdarg >= 0)
  963.       cursidenumber = cmdarg;
  964.     notify(dside, "will now be creating side %d %s units.",
  965.            cursidenumber, u_type_name(u));
  966.     }
  967. }
  968.  
  969. void
  970. do_c_add_unit()
  971. {
  972.     Unit *unit;
  973.  
  974.     if (!check_designer_status("create units"))
  975.       return;
  976.     unit = designer_create_unit(dside, curutype, cursidenumber, curx, cury);
  977.     if (unit != NULL) {
  978.     make_current(unit);
  979.     } else {
  980.     cmd_error("Unit creation failed!");
  981.     }
  982. }
  983.  
  984. void
  985. do_c_set_terrain_type()
  986. {
  987.     int t;
  988.  
  989.     if (!check_designer_status("set ttypes to paint"))
  990.       return;
  991.     t = ask_terrain_type("Type of terrain: ", NULL);
  992.     if (t != NONTTYPE) {
  993.     curttype = t;
  994.     if (cmdarg >= 0)
  995.       curradius = cmdarg;
  996.     notify(dside, "will now be painting %d-radius %s.",
  997.            curradius, t_type_name(t));
  998.     }
  999. }
  1000.  
  1001. /* Terrain painting command. */
  1002.  
  1003. void
  1004. do_c_paint_terrain()
  1005. {
  1006.     int t;
  1007.  
  1008.     /* (should ask for dir for linear types?) */
  1009.     if (!check_designer_status("paint terrain"))
  1010.       return;
  1011.     /* If command's arg is nonegative, interpret as temporary
  1012.        change of terrain type. */
  1013.     t = (cmdarg >= 0 ? cmdarg : curttype);
  1014.     paint_cell(dside, curx, cury, curradius, t);
  1015. }
  1016.  
  1017. /* (should add painting for all other layers here) */
  1018.  
  1019. #endif /* DESIGNERS */
  1020.  
  1021. #ifdef DEBUGGING
  1022.  
  1023. void
  1024. do_debug()
  1025. {
  1026. #ifndef Debug
  1027.     Debug = !Debug;
  1028. #endif
  1029. }
  1030.  
  1031. void
  1032. do_debugg()
  1033. {
  1034. #ifndef DebugG
  1035.     DebugG = !DebugG;
  1036. #endif
  1037. }
  1038.  
  1039. void
  1040. do_debugm()
  1041. {
  1042. #ifndef DebugM
  1043.     DebugM = !DebugM;
  1044. #endif
  1045. }
  1046.  
  1047. #endif /* DEBUGGING */
  1048.  
  1049. /* Search in command table and execute function if found, complaining if
  1050.    the command is not recognized.  Many commands operate on the "current
  1051.    unit", and all uniformly error out if there is no current unit, so put
  1052.    that test here.  Also fix up the arg if the value passed is one of the
  1053.    specially recognized ones. */
  1054.  
  1055. void
  1056. execute_command()
  1057. {
  1058.     if (execute_command_from_table(ccommands))
  1059.       return;
  1060.     if (execute_command_from_table(commands))
  1061.       return;
  1062.     cmd_error("unknown command character '%c'", inpch);
  1063. }
  1064.  
  1065. char tmpkey;
  1066.  
  1067. static int
  1068. execute_command_from_table(cmdtab)
  1069. CmdTab *cmdtab;
  1070. {
  1071.     CmdTab *cmd;
  1072.     char ch = inpch;
  1073.     int sx = -1, sy = -1;
  1074.     void (*fn) PROTO ((void));
  1075.     
  1076.     for (cmd = cmdtab; cmd->name != NULL; ++cmd) {
  1077.     if (ch == cmd->fchar) {
  1078.         fn = cmd->fn;
  1079.         if (fn == NULL) {
  1080.         run_warning("no command function for %s (0x%x)?",
  1081.                 cmd->name, ch);
  1082.         return TRUE;
  1083.         }
  1084.         tmpkey = ch;
  1085.         (*fn)();
  1086.         /* Whatever might have happened, we *did* find the command. */
  1087.         return TRUE;
  1088.     }
  1089.     }
  1090.     return FALSE;
  1091. }
  1092.  
  1093. static void
  1094. execute_named_command(cmdstr)
  1095. char *cmdstr;
  1096. {
  1097.     /* Look for the command name in the curses-specific table. */
  1098.     if (execute_named_command_from_table(cmdstr, ccommands))
  1099.       return;
  1100.     /* Try the generic table. */
  1101.     if (execute_named_command_from_table(cmdstr, commands))
  1102.       return;
  1103.     cmd_error("unknown command name \"%s\"", cmdstr);
  1104. }
  1105.  
  1106. static int
  1107. execute_named_command_from_table(cmdstr, cmdtab)
  1108. char *cmdstr;
  1109. CmdTab *cmdtab;
  1110. {
  1111.     CmdTab *cmd;
  1112.     void (*fn) PROTO ((void));
  1113.  
  1114.     for (cmd = cmdtab; cmd->name != NULL; ++cmd) {
  1115.     if (strcmp(cmdstr, cmd->name) == 0) {
  1116.         if ((fn = cmd->fn) == NULL) {
  1117.         run_warning("no command function for %s?", cmd->name);
  1118.         return TRUE;
  1119.         }
  1120.         tmpkey = cmd->fchar;
  1121.         (*fn)();
  1122.         /* Whatever might have happened, we *did* find the command. */
  1123.         return TRUE;
  1124.     }
  1125.     }
  1126.     return FALSE;
  1127. }
  1128.  
  1129. /* Paste one-line descriptions of commands into the supplied buffer. */
  1130.  
  1131. static void
  1132. describe_commands(arg, key, buf)
  1133. int arg;
  1134. char *key, *buf;
  1135. {
  1136.     sprintf(spbuf, "To move a unit, use [hlyubn]\n");
  1137.     append_to_buffer(buf, spbuf);
  1138.     sprintf(spbuf, "[HLYUBN] moves unit repeatedly in that direction\n");
  1139.     append_to_buffer(buf, spbuf);
  1140.     sprintf(spbuf, "To look at another unit, use survey mode ('z')\n");
  1141.     append_to_buffer(buf, spbuf);
  1142.     sprintf(spbuf, "and use [hlyubnHLYUBN] to move the cursor\n");
  1143.     append_to_buffer(buf, spbuf);
  1144.     sprintf(spbuf, "\n");
  1145.     append_to_buffer(buf, spbuf);
  1146.     sprintf(spbuf, "Generic commands:\n");
  1147.     append_to_buffer(buf, spbuf);
  1148.     describe_command_table(arg, key, buf, commands);
  1149.     sprintf(spbuf, "Cconq-specific commands:\n");
  1150.     describe_command_table(arg, key, buf, ccommands);
  1151. }
  1152.  
  1153. static void
  1154. describe_command_table(arg, key, buf, cmdtab)
  1155. int arg;
  1156. char *key, *buf;
  1157. CmdTab *cmdtab;
  1158. {
  1159.     CmdTab *cmd;
  1160.  
  1161.     strcat(buf, "Single-key commands:\n\n");
  1162.     for (cmd = cmdtab; cmd->name != NULL; ++cmd) {
  1163.     describe_command (cmd->fchar, cmd->name, cmd->help, TRUE, buf);
  1164.     }
  1165.     strcat(buf, "\nLong name commands:\n\n");
  1166.     for (cmd = cmdtab; cmd->name != NULL; ++cmd) {
  1167.     describe_command (cmd->fchar, cmd->name, cmd->help, FALSE, buf);
  1168.     }
  1169. }
  1170.  
  1171. /* Generic command error routine just does a notify. */
  1172.  
  1173. static void
  1174. #ifdef __STDC__
  1175. cmd_error(char *fmt, ...)
  1176. #else
  1177. cmd_error(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
  1178. char *fmt;
  1179. long a1, a2, a3, a4, a5, a6, a7, a8, a9;
  1180. #endif
  1181. {
  1182.     char tmpnbuf[BUFSIZE];
  1183. #ifdef __STDC__
  1184.     {
  1185.     va_list ap;
  1186.  
  1187.     va_start(ap, fmt);
  1188.     vsprintf(tmpnbuf, fmt, ap);
  1189.     va_end(ap);
  1190.     }
  1191. #else
  1192.     sprintf(tmpnbuf, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
  1193. #endif
  1194.     low_notify(tmpnbuf);
  1195.     xbeep();
  1196. }
  1197.